//this hash map use unordered_map from stl and  inhert from GMap
//andycai_sc implement 2011-04-24

#ifndef GSTDHASHMAP_H
#define GSTDHASHMAP_H

#include "GTpl/IGMap.h"

#include <unordered_map>

using std::unordered_map;
using std::pair;
using std::iterator;

template< typename Key, typename Value, typename HashFunc = std::hash<Key> >
class GHashMap : public GMap<Key, Value>
{
public:
    GHashMap() {}
    virtual ~GHashMap() {}

    typename GMap<Key, Value>::IterPtr insert(const Key& key, const Value& value);

    int erase(const Key& key);
    void erase(typename GMap<Key, Value>::IterPtr position);

    typename GMap<Key, Value>::IterPtr find(const Key& key);

    typename GMap<Key, Value>::IterPtr begin();
    typename GMap<Key, Value>::IterPtr end();

private:
    unordered_map<Key, Value, HashFunc> m_hashMap;
    class HIterator : public GMap<Key, Value>::Iterator
    {
    public:
        HIterator(const typename unordered_map<Key, Value, HashFunc>::iterator& it) { m_iter = it; }
		HIterator(const HIterator& hIt) { m_iter = hIt.m_iter; }
		typename GMap<Key, Value>::Iterator* clone();
        virtual ~HIterator() {}
        const Key& getKey();
        Value& getValue();
        typename GMap<Key, Value>::Iterator& operator++();
        typename GMap<Key, Value>::Iterator& operator++(int);
        bool operator==(const typename GMap<Key, Value>::Iterator&) const;
        bool operator!=(const typename GMap<Key, Value>::Iterator&) const;

        typename unordered_map<Key, Value, HashFunc>::iterator getOrigIter() const
        {
            return m_iter;
        }
    private:
        typename unordered_map<Key, Value, HashFunc>::iterator m_iter;
    };
};

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::insert(const Key& key, const Value& value)
{
    pair< typename unordered_map<Key, Value, HashFunc>::iterator, bool > rp = m_hashMap.insert(typename unordered_map<Key, Value, HashFunc>::value_type(key, value));
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(rp.first));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
int GHashMap<Key, Value, HashFunc>::erase(const Key& key)
{
    return m_hashMap.erase(key);
}

template<typename Key, typename Value, typename HashFunc>
void GHashMap<Key, Value, HashFunc>::erase(typename GMap<Key, Value>::IterPtr position)
{
    HIterator* hIt = dynamic_cast<HIterator*>(position.get());
    assert(hIt != 0);
    m_hashMap.erase(hIt->getOrigIter());
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::find(const Key& key)
{
    typename unordered_map<Key, Value, HashFunc>::iterator it = m_hashMap.find(key);
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::begin()
{
    typename unordered_map<Key, Value, HashFunc>::iterator it = m_hashMap.begin();
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMap<Key, Value, HashFunc>::end()
{
    typename unordered_map<Key, Value, HashFunc>::iterator it = m_hashMap.end();
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator* GHashMap<Key, Value, HashFunc>::HIterator::clone()
{
	return new HIterator(*this);
}

template<typename Key, typename Value, typename HashFunc>
const Key& GHashMap<Key, Value, HashFunc>::HIterator::getKey()
{
    return m_iter->first;
}

template<typename Key, typename Value, typename HashFunc>
Value& GHashMap<Key, Value, HashFunc>::HIterator::getValue()
{
    return m_iter->second;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMap<Key, Value, HashFunc>::HIterator::operator++()
{
    m_iter++;
    return *this;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMap<Key, Value, HashFunc>::HIterator::operator++(int)
{
    ++m_iter;
    return *this;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMap<Key, Value, HashFunc>::HIterator::operator==(const typename GMap<Key, Value>::Iterator& it) const
{
    const HIterator& hIt = dynamic_cast<const HIterator&>(it);
    return m_iter == hIt.m_iter;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMap<Key, Value, HashFunc>::HIterator::operator!=(const typename GMap<Key, Value>::Iterator& it) const
{
    const HIterator& hIt = dynamic_cast<const HIterator&>(it);
    return m_iter != hIt.m_iter;
}

//----------------------GHashMultiMap implement-----------------------------------------

using std::unordered_multimap;

template< typename Key, typename Value, typename HashFunc = std::hash<Key> >
class GHashMultiMap : public GMap<Key, Value>
{
public:
    GHashMultiMap() {}
    virtual ~GHashMultiMap() {}

    typename GMap<Key, Value>::IterPtr insert(const Key& key, const Value& value);

    int erase(const Key& key);
    void erase(typename GMap<Key, Value>::IterPtr position);

    typename GMap<Key, Value>::IterPtr find(const Key& key);

    typename GMap<Key, Value>::IterPtr begin();
    typename GMap<Key, Value>::IterPtr end();

    typename GMap<Key, Value>::Range equal_range(const Key& key);

private:
    unordered_multimap<Key, Value, HashFunc> m_hashMap;
    class HIterator : public GMap<Key, Value>::Iterator
    {
    public:
        HIterator(const typename unordered_multimap<Key, Value, HashFunc>::iterator& it) { m_iter = it; }
		HIterator(const HIterator& hIt) { m_iter = hIt.m_iter; }
        ~HIterator() {}
		typename GMap<Key, Value>::Iterator* clone();
        const Key& getKey();
        Value& getValue();
        typename GMap<Key, Value>::Iterator& operator++();
        typename GMap<Key, Value>::Iterator& operator++(int);
        bool operator==(const typename GMap<Key, Value>::Iterator&) const;
        bool operator!=(const typename GMap<Key, Value>::Iterator&) const;

        typename unordered_multimap<Key, Value, HashFunc>::iterator getOrigIter() const
        {
            return m_iter;
        }
    private:
        typename unordered_multimap<Key, Value, HashFunc>::iterator m_iter;
    };
};

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, HashFunc>::insert(const Key& key, const Value& value)
{
    typename unordered_multimap<Key, Value, HashFunc>::iterator it = m_hashMap.insert(typename unordered_multimap<Key, Value, HashFunc>::value_type(key, value));
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
int GHashMultiMap<Key, Value, HashFunc>::erase(const Key& key)
{
    return m_hashMap.erase(key);
}

template<typename Key, typename Value, typename HashFunc>
void GHashMultiMap<Key, Value, HashFunc>::erase(typename GMap<Key, Value>::IterPtr position)
{
    HIterator* hIt = dynamic_cast<HIterator*>(position.get());
    assert(hIt != 0);
    m_hashMap.erase(hIt->getOrigIter());
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, HashFunc>::find(const Key& key)
{
    typename unordered_multimap<Key, Value, HashFunc>::iterator it = m_hashMap.find(key);
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, HashFunc>::begin()
{
    typename unordered_multimap<Key, Value, HashFunc>::iterator it = m_hashMap.begin();
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::IterPtr GHashMultiMap<Key, Value, HashFunc>::end()
{
    typename unordered_multimap<Key, Value, HashFunc>::iterator it = m_hashMap.end();
    typename GMap<Key, Value>::IterPtr itPtr(new HIterator(it));
    return itPtr;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Range GHashMultiMap<Key, Value, HashFunc>::equal_range(const Key& key)
{
    pair<typename unordered_multimap<Key, Value, HashFunc>::iterator, typename unordered_multimap<Key, Value, HashFunc>::iterator> eqRet;
    eqRet = m_hashMap.equal_range(key);
    typename GMap<Key, Value>::IterPtr itPtrF(new HIterator(eqRet.first));
    typename GMap<Key, Value>::IterPtr itPtrL(new HIterator(eqRet.second));
    return typename GMap<Key, Value>::Range(itPtrF, itPtrL);
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator* GHashMultiMap<Key, Value, HashFunc>::HIterator::clone()
{
	return new HIterator(*this);
}

template<typename Key, typename Value, typename HashFunc>
const Key& GHashMultiMap<Key, Value, HashFunc>::HIterator::getKey()
{
    return m_iter->first;
}

template<typename Key, typename Value, typename HashFunc>
Value& GHashMultiMap<Key, Value, HashFunc>::HIterator::getValue()
{
    return m_iter->second;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMultiMap<Key, Value, HashFunc>::HIterator::operator++()
{
    m_iter++;
    return *this;
}

template<typename Key, typename Value, typename HashFunc>
typename GMap<Key, Value>::Iterator& GHashMultiMap<Key, Value, HashFunc>::HIterator::operator++(int)
{
    ++m_iter;
    return *this;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMultiMap<Key, Value, HashFunc>::HIterator::operator==(const typename GMap<Key, Value>::Iterator& it) const
{
    const HIterator& hIt = dynamic_cast<const HIterator&>(it);
    return m_iter == hIt.m_iter;
}

template<typename Key, typename Value, typename HashFunc>
bool GHashMultiMap<Key, Value, HashFunc>::HIterator::operator!=(const typename GMap<Key, Value>::Iterator& it) const
{
    const HIterator& hIt = dynamic_cast<const HIterator&>(it);
    return m_iter != hIt.m_iter;
}

#endif // GHASHMAP_H
